`include "defines.v"
module fronted(
  input clk,
  input rst_n,
  // boot
  input [`VADDR_W-1: 0] boot_addr,
  // 流水线控制信号
  input                 ctrl_fronted_flush_i       ,
  input                 ctrl_baq_flush_i           ,
  input                 commit_fronted_invalidate_i,
  // commit 的 异常处理信号
  input                 commit_fronted_exception_i  ,
  input  [`VADDR_W-1:0] commit_fronted_exceptionPC_i,
  // bru 的 错误分支预测修正信号
  input                 bru_fronted_misPredict_i,
  input                 bru_fronted_valid_i     ,
  input                 bru_fronted_brunch_i    ,
  input  [`VADDR_W-1:0] bru_fronted_JumpOldPC_i ,
  input  [`VADDR_W-1:0] bru_fronted_misPrePC_i  ,
  // 输出到 IDU的 指令信号
  output                fronted_idu_valid_o     ,
  input                 idu_fronted_ready_i     ,
  output [31:0]         fronted_idu_instr_o     ,
  output [`VADDR_W-1:0] fronted_idu_pc_o        ,
  output                fronted_idu_pre_o       ,
  // MMU 预留接口
  output                fronted_mmu_trans_valid_o,
  input                 mmu_fronted_trans_ready_i,
  output [`VADDR_W-1:0] fronted_mmu_trans_vaddr_o,
  input  [`PADDR_W-1:0] mmu_fronted_trans_paddr_i,
  // 访存接口 Imem 只有读
  output                fronted_mem_addr_valid_o ,
  input                 mem_fronted_data_valid_i ,
  output [`PADDR_W-1:0] fronted_mem_addr_o       ,
  input  [127:0]        mem_fronted_data_i       
`ifdef PREDICT_PC
  ,
  // BAQ to BRU 
  output                baq_bru_valid_o,
  input                 bru_baq_ready_i,
  output [`VADDR_W-1:0] baq_bru_dout_o
`endif
);
wire                 ifu_icache_valid     ;
wire                 icache_ifu_ready     ;
wire  [`VADDR_W-1:0] ifu_icache_req_addr  ;
wire                 icache_ibf_data_valid;
wire                 ibf_icache_data_ready;
wire [`VADDR_W-1:0]  icache_ibf_vaddr     ;
wire [31:0]          icache_ibf_instr     ;
// wire                 ras_ifu_valid;
// wire [`VADDR_W-1:0]  ras_ifu_addr ;
wire                 bpu_ifu_valid;
wire [`VADDR_W-1:0]  bpu_ifu_predict_addr;
wire btb_hit;
wire bht_taken;
wire internaFlush;
wire insrtScan_ras_Call;
wire insrtScan_ras_Ret ;
wire ras_taken;
wire icache_ibf_pre;
wire ifu_baq_valid;
wire baq_ifu_ready;
wire [`VADDR_W-1:0]ifu_baq_din  ;
wire ifu_icache_pre;
wire [`VADDR_W-1:0] ifu_bpu_pc;
ifu IFU(
  .clk         (clk      ),
  .rst_n       (rst_n    ),
  .boot_addr   (boot_addr),
  // commit 的 异常处理信号
  .commit_ifu_exception_i   ( commit_fronted_exception_i   ),
  .commit_ifu_exceptionPC_i ( commit_fronted_exceptionPC_i ),
  // bru 的 错误分支预测修正信号
  .bru_ifu_valid_i     ( bru_fronted_valid_i && bru_fronted_misPredict_i),
  .bru_ifu_JumpOldPC_i ( bru_fronted_JumpOldPC_i),
`ifdef PREDICT_PC  
  // RAS 
  .ras_ifu_valid_i ( 'd0 ),
  .ras_ifu_addr_i  ( 'd0 ),
  // BTB & BHT
  .bpu_ifu_valid_i        ( bpu_ifu_valid        ),
  .bpu_ifu_predict_addr_i ( bpu_ifu_predict_addr ),
  .ifu_bpu_pc_o           ( ifu_bpu_pc ),
`endif
  // icache
  .ifu_icache_valid_o    ( ifu_icache_valid    ),
  .icache_ifu_ready_i    ( icache_ifu_ready    ),
  .ifu_icache_req_addr_o ( ifu_icache_req_addr ),
  .ifu_icache_pre_o      ( ifu_icache_pre      )
`ifdef PREDICT_PC
  // BAQ in
  ,
  .ifu_baq_valid_o       ( ifu_baq_valid       ),
  .baq_ifu_ready_i       ( baq_ifu_ready       ),
  .ifu_baq_din_o         ( ifu_baq_din         )
`endif
);  
`ifdef PREDICT_PC
brunchAddressQueue BAQ(
  .clk              ( clk ),
  .rst_n            ( rst_n ),
  .ctrl_baq_flush_i ( ctrl_baq_flush_i ),
  // In Quene
  .ifu_baq_valid_i( ifu_baq_valid ),
  .baq_ifu_ready_o( baq_ifu_ready ),
  .ifu_baq_din_i  ( ifu_baq_din   ),
  // Out Queue
  .baq_bru_valid_o ( baq_bru_valid_o ),
  .bru_baq_ready_i ( bru_baq_ready_i ),
  .baq_bru_dout_o  ( baq_bru_dout_o  )
); 

btb BTB(
  .clk  (clk),
  .rst_n(rst_n),
  // 查询路径
  .gen_btb_pc_i ( ifu_bpu_pc  ),
  .hit_o        ( btb_hit              ),
  .predict_pc_o ( bpu_ifu_predict_addr ),
  // 更新路径
  .ex_btb_valid_i   ( bru_fronted_valid_i      ),
  .ex_btb_branch_i  ( bru_fronted_brunch_i     ),
  .ex_btb_pc_i      ( bru_fronted_misPrePC_i   ),
  .ex_btb_jump_pc_i ( bru_fronted_JumpOldPC_i  ) 
);

bht BHT(
  .clk  (clk),
  .rst_n(rst_n),
  // check
  .gen_bht_pc_i ( ifu_bpu_pc ),
  .taken_o      ( bht_taken    ),
  // update
  .ex_bht_valid_i  ( bru_fronted_valid_i ),
  .ex_bht_brunch_i ( bru_fronted_brunch_i ),
  .ex_bht_pc_i     ( bru_fronted_misPrePC_i )
);
assign bpu_ifu_valid = btb_hit && bht_taken;
`endif

PipelineIcache Icache(
  .clk   ( clk   ),
  .rst_n ( rst_n ),
  .flush ( ctrl_fronted_flush_i ),
  .internaFlush('d0),
  .invalidate(commit_fronted_invalidate_i),
  // request port 
  .ifu_icache_addr_valid_i ( ifu_icache_valid    ),
  .icache_ifu_addr_ready_o ( icache_ifu_ready    ),
  .ifu_icache_vaddr_i      ( ifu_icache_req_addr ),
  .ifu_icache_pre_i        ( ifu_icache_pre      ),
  // MMU address translation
  .icache_mmu_trans_valid_o ( fronted_mmu_trans_valid_o ),
  .mmu_icache_trans_ready_i ( mmu_fronted_trans_ready_i ),
  .icache_mmu_trans_vaddr_o ( fronted_mmu_trans_vaddr_o ),
  .mmu_icache_trans_paddr_i ( mmu_fronted_trans_paddr_i ),
  // resp port
  .icache_ibf_data_valid_o ( icache_ibf_data_valid ),
  .ibf_icache_data_ready_i ( ibf_icache_data_ready ),
  .icache_ibf_vaddr_o      ( icache_ibf_vaddr      ),
  .icache_ibf_instr_o      ( icache_ibf_instr      ),
  .icache_ibf_pre_o        ( icache_ibf_pre        ),
  // mem port
  .icache_mem_paddr_valid_o ( fronted_mem_addr_valid_o ),
  .icache_mem_paddr_o       ( fronted_mem_addr_o       ),
  .mem_icache_data_valid_i  ( mem_fronted_data_valid_i ),
  .mem_icache_data_i        ( mem_fronted_data_i       ) 
);

// instrScan InstrScan(
//   .instr ( icache_ibf_instr ),
//   .insrtScan_ras_Call_o ( insrtScan_ras_Call ),
//   .insrtScan_ras_Ret_o  ( insrtScan_ras_Ret  )
// );

// ras RAS(
//   .clk   ( clk   ),
//   .rst_n ( rst_n ),
//   .valid ( icache_ibf_data_valid && ibf_icache_data_ready),
//   .isCall( insrtScan_ras_Call ),
//   .isRet ( insrtScan_ras_Ret  ),
//   .gen_ras_pc_i( icache_ibf_vaddr ),
//   .taken_o           ( ras_ifu_valid ),
//   .ras_gen_jump_pc_o ( ras_ifu_addr  )
// );
// assign internaFlush = ras_ifu_valid;
instrBuffer#(
  .DataW(64+1),// instr + pc 
  .Depth(4)
) IBF (
  .clk(clk),
  .rst_n(rst_n),
  .flush(ctrl_fronted_flush_i),

  .in_valid(icache_ibf_data_valid),
  .in_ready(ibf_icache_data_ready),
  .din({icache_ibf_pre,icache_ibf_vaddr,icache_ibf_instr}),

  .out_valid(fronted_idu_valid_o),
  .out_ready(idu_fronted_ready_i),
  .dout({fronted_idu_pre_o,fronted_idu_pc_o,fronted_idu_instr_o})
);

endmodule